function [corr_count] = hamming_8b10b()
%HAMMING_8B10B Analyze Hamming-distance statistics
%   For each potential 10-bit input codeword, find the number of
%   valid 8b/10b codewords for which a single bit error would be
%   "correctable".  i.e., What fraction of the inputs have a unique
%   solution with Hamming distance <= 1.

% Copyright 2019 The Aerospace Corporation
%
% This file is part of SatCat5.
%
% SatCat5 is free software: you can redistribute it and/or modify it under
% the terms of the GNU Lesser General Public License as published by the
% Free Software Foundation, either version 3 of the License, or (at your
% option) any later version.
%
% SatCat5 is distributed in the hope that it will be useful, but WITHOUT
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
% License for more details.
%
% You should have received a copy of the GNU Lesser General Public License
% along with SatCat5.  If not, see <https://www.gnu.org/licenses/>.

% Define all valid RD- codewords.
rdm_str = { ...
    '1001110100', ...
    '0111010100', ...
    '1011010100', ...
    '1100011011', ...
    '1101010100', ...
    '1010011011', ...
    '0110011011', ...
    '1110001011', ...
    '1110010100', ...
    '1001011011', ...
    '0101011011', ...
    '1101001011', ...
    '0011011011', ...
    '1011001011', ...
    '0111001011', ...
    '0101110100', ...
    '0110110100', ...
    '1000111011', ...
    '0100111011', ...
    '1100101011', ...
    '0010111011', ...
    '1010101011', ...
    '0110101011', ...
    '1110100100', ...
    '1100110100', ...
    '1001101011', ...
    '0101101011', ...
    '1101100100', ...
    '0011101011', ...
    '1011100100', ...
    '0111100100', ...
    '1010110100', ...
    '1001111001', ...
    '0111011001', ...
    '1011011001', ...
    '1100011001', ...
    '1101011001', ...
    '1010011001', ...
    '0110011001', ...
    '1110001001', ...
    '1110011001', ...
    '1001011001', ...
    '0101011001', ...
    '1101001001', ...
    '0011011001', ...
    '1011001001', ...
    '0111001001', ...
    '0101111001', ...
    '0110111001', ...
    '1000111001', ...
    '0100111001', ...
    '1100101001', ...
    '0010111001', ...
    '1010101001', ...
    '0110101001', ...
    '1110101001', ...
    '1100111001', ...
    '1001101001', ...
    '0101101001', ...
    '1101101001', ...
    '0011101001', ...
    '1011101001', ...
    '0111101001', ...
    '1010111001', ...
    '1001110101', ...
    '0111010101', ...
    '1011010101', ...
    '1100010101', ...
    '1101010101', ...
    '1010010101', ...
    '0110010101', ...
    '1110000101', ...
    '1110010101', ...
    '1001010101', ...
    '0101010101', ...
    '1101000101', ...
    '0011010101', ...
    '1011000101', ...
    '0111000101', ...
    '0101110101', ...
    '0110110101', ...
    '1000110101', ...
    '0100110101', ...
    '1100100101', ...
    '0010110101', ...
    '1010100101', ...
    '0110100101', ...
    '1110100101', ...
    '1100110101', ...
    '1001100101', ...
    '0101100101', ...
    '1101100101', ...
    '0011100101', ...
    '1011100101', ...
    '0111100101', ...
    '1010110101', ...
    '1001110011', ...
    '0111010011', ...
    '1011010011', ...
    '1100011100', ...
    '1101010011', ...
    '1010011100', ...
    '0110011100', ...
    '1110001100', ...
    '1110010011', ...
    '1001011100', ...
    '0101011100', ...
    '1101001100', ...
    '0011011100', ...
    '1011001100', ...
    '0111001100', ...
    '0101110011', ...
    '0110110011', ...
    '1000111100', ...
    '0100111100', ...
    '1100101100', ...
    '0010111100', ...
    '1010101100', ...
    '0110101100', ...
    '1110100011', ...
    '1100110011', ...
    '1001101100', ...
    '0101101100', ...
    '1101100011', ...
    '0011101100', ...
    '1011100011', ...
    '0111100011', ...
    '1010110011', ...
    '1001110010', ...
    '0111010010', ...
    '1011010010', ...
    '1100011101', ...
    '1101010010', ...
    '1010011101', ...
    '0110011101', ...
    '1110001101', ...
    '1110010010', ...
    '1001011101', ...
    '0101011101', ...
    '1101001101', ...
    '0011011101', ...
    '1011001101', ...
    '0111001101', ...
    '0101110010', ...
    '0110110010', ...
    '1000111101', ...
    '0100111101', ...
    '1100101101', ...
    '0010111101', ...
    '1010101101', ...
    '0110101101', ...
    '1110100010', ...
    '1100110010', ...
    '1001101101', ...
    '0101101101', ...
    '1101100010', ...
    '0011101101', ...
    '1011100010', ...
    '0111100010', ...
    '1010110010', ...
    '1001111010', ...
    '0111011010', ...
    '1011011010', ...
    '1100011010', ...
    '1101011010', ...
    '1010011010', ...
    '0110011010', ...
    '1110001010', ...
    '1110011010', ...
    '1001011010', ...
    '0101011010', ...
    '1101001010', ...
    '0011011010', ...
    '1011001010', ...
    '0111001010', ...
    '0101111010', ...
    '0110111010', ...
    '1000111010', ...
    '0100111010', ...
    '1100101010', ...
    '0010111010', ...
    '1010101010', ...
    '0110101010', ...
    '1110101010', ...
    '1100111010', ...
    '1001101010', ...
    '0101101010', ...
    '1101101010', ...
    '0011101010', ...
    '1011101010', ...
    '0111101010', ...
    '1010111010', ...
    '1001110110', ...
    '0111010110', ...
    '1011010110', ...
    '1100010110', ...
    '1101010110', ...
    '1010010110', ...
    '0110010110', ...
    '1110000110', ...
    '1110010110', ...
    '1001010110', ...
    '0101010110', ...
    '1101000110', ...
    '0011010110', ...
    '1011000110', ...
    '0111000110', ...
    '0101110110', ...
    '0110110110', ...
    '1000110110', ...
    '0100110110', ...
    '1100100110', ...
    '0010110110', ...
    '1010100110', ...
    '0110100110', ...
    '1110100110', ...
    '1100110110', ...
    '1001100110', ...
    '0101100110', ...
    '1101100110', ...
    '0011100110', ...
    '1011100110', ...
    '0111100110', ...
    '1010110110', ...
    '1001110001', ...
    '0111010001', ...
    '1011010001', ...
    '1100011110', ...
    '1101010001', ...
    '1010011110', ...
    '0110011110', ...
    '1110001110', ...
    '1110010001', ...
    '1001011110', ...
    '0101011110', ...
    '1101001110', ...
    '0011011110', ...
    '1011001110', ...
    '0111001110', ...
    '0101110001', ...
    '0110110001', ...
    '1000110111', ...
    '0100110111', ...
    '1100101110', ...
    '0010110111', ...
    '1010101110', ...
    '0110101110', ...
    '1110100001', ...
    '1100110001', ...
    '1001101110', ...
    '0101101110', ...
    '1101100001', ...
    '0011101110', ...
    '1011100001', ...
    '0111100001', ...
    '1010110001', ...
    '0011110100', ...
    '0011111001', ...
    '0011110101', ...
    '0011110011', ...
    '0011110010', ...
    '0011111010', ...
    '0011110110', ...
    '0011111000', ...
    '1110101000', ...
    '1101101000', ...
    '1011101000', ...
    '0111101000'};

% Define all valid RD+ codewords.
rdp_str = { ...
    '0110001011', ...
    '1000101011', ...
    '0100101011', ...
    '1100010100', ...
    '0010101011', ...
    '1010010100', ...
    '0110010100', ...
    '0001110100', ...
    '0001101011', ...
    '1001010100', ...
    '0101010100', ...
    '1101000100', ...
    '0011010100', ...
    '1011000100', ...
    '0111000100', ...
    '1010001011', ...
    '1001001011', ...
    '1000110100', ...
    '0100110100', ...
    '1100100100', ...
    '0010110100', ...
    '1010100100', ...
    '0110100100', ...
    '0001011011', ...
    '0011001011', ...
    '1001100100', ...
    '0101100100', ...
    '0010011011', ...
    '0011100100', ...
    '0100011011', ...
    '1000011011', ...
    '0101001011', ...
    '0110001001', ...
    '1000101001', ...
    '0100101001', ...
    '1100011001', ...
    '0010101001', ...
    '1010011001', ...
    '0110011001', ...
    '0001111001', ...
    '0001101001', ...
    '1001011001', ...
    '0101011001', ...
    '1101001001', ...
    '0011011001', ...
    '1011001001', ...
    '0111001001', ...
    '1010001001', ...
    '1001001001', ...
    '1000111001', ...
    '0100111001', ...
    '1100101001', ...
    '0010111001', ...
    '1010101001', ...
    '0110101001', ...
    '0001011001', ...
    '0011001001', ...
    '1001101001', ...
    '0101101001', ...
    '0010011001', ...
    '0011101001', ...
    '0100011001', ...
    '1000011001', ...
    '0101001001', ...
    '0110000101', ...
    '1000100101', ...
    '0100100101', ...
    '1100010101', ...
    '0010100101', ...
    '1010010101', ...
    '0110010101', ...
    '0001110101', ...
    '0001100101', ...
    '1001010101', ...
    '0101010101', ...
    '1101000101', ...
    '0011010101', ...
    '1011000101', ...
    '0111000101', ...
    '1010000101', ...
    '1001000101', ...
    '1000110101', ...
    '0100110101', ...
    '1100100101', ...
    '0010110101', ...
    '1010100101', ...
    '0110100101', ...
    '0001010101', ...
    '0011000101', ...
    '1001100101', ...
    '0101100101', ...
    '0010010101', ...
    '0011100101', ...
    '0100010101', ...
    '1000010101', ...
    '0101000101', ...
    '0110001100', ...
    '1000101100', ...
    '0100101100', ...
    '1100010011', ...
    '0010101100', ...
    '1010010011', ...
    '0110010011', ...
    '0001110011', ...
    '0001101100', ...
    '1001010011', ...
    '0101010011', ...
    '1101000011', ...
    '0011010011', ...
    '1011000011', ...
    '0111000011', ...
    '1010001100', ...
    '1001001100', ...
    '1000110011', ...
    '0100110011', ...
    '1100100011', ...
    '0010110011', ...
    '1010100011', ...
    '0110100011', ...
    '0001011100', ...
    '0011001100', ...
    '1001100011', ...
    '0101100011', ...
    '0010011100', ...
    '0011100011', ...
    '0100011100', ...
    '1000011100', ...
    '0101001100', ...
    '0110001101', ...
    '1000101101', ...
    '0100101101', ...
    '1100010010', ...
    '0010101101', ...
    '1010010010', ...
    '0110010010', ...
    '0001110010', ...
    '0001101101', ...
    '1001010010', ...
    '0101010010', ...
    '1101000010', ...
    '0011010010', ...
    '1011000010', ...
    '0111000010', ...
    '1010001101', ...
    '1001001101', ...
    '1000110010', ...
    '0100110010', ...
    '1100100010', ...
    '0010110010', ...
    '1010100010', ...
    '0110100010', ...
    '0001011101', ...
    '0011001101', ...
    '1001100010', ...
    '0101100010', ...
    '0010011101', ...
    '0011100010', ...
    '0100011101', ...
    '1000011101', ...
    '0101001101', ...
    '0110001010', ...
    '1000101010', ...
    '0100101010', ...
    '1100011010', ...
    '0010101010', ...
    '1010011010', ...
    '0110011010', ...
    '0001111010', ...
    '0001101010', ...
    '1001011010', ...
    '0101011010', ...
    '1101001010', ...
    '0011011010', ...
    '1011001010', ...
    '0111001010', ...
    '1010001010', ...
    '1001001010', ...
    '1000111010', ...
    '0100111010', ...
    '1100101010', ...
    '0010111010', ...
    '1010101010', ...
    '0110101010', ...
    '0001011010', ...
    '0011001010', ...
    '1001101010', ...
    '0101101010', ...
    '0010011010', ...
    '0011101010', ...
    '0100011010', ...
    '1000011010', ...
    '0101001010', ...
    '0110000110', ...
    '1000100110', ...
    '0100100110', ...
    '1100010110', ...
    '0010100110', ...
    '1010010110', ...
    '0110010110', ...
    '0001110110', ...
    '0001100110', ...
    '1001010110', ...
    '0101010110', ...
    '1101000110', ...
    '0011010110', ...
    '1011000110', ...
    '0111000110', ...
    '1010000110', ...
    '1001000110', ...
    '1000110110', ...
    '0100110110', ...
    '1100100110', ...
    '0010110110', ...
    '1010100110', ...
    '0110100110', ...
    '0001010110', ...
    '0011000110', ...
    '1001100110', ...
    '0101100110', ...
    '0010010110', ...
    '0011100110', ...
    '0100010110', ...
    '1000010110', ...
    '0101000110', ...
    '0110001110', ...
    '1000101110', ...
    '0100101110', ...
    '1100010001', ...
    '0010101110', ...
    '1010010001', ...
    '0110010001', ...
    '0001110001', ...
    '0001101110', ...
    '1001010001', ...
    '0101010001', ...
    '1101001000', ...
    '0011010001', ...
    '1011001000', ...
    '0111001000', ...
    '1010001110', ...
    '1001001110', ...
    '1000110001', ...
    '0100110001', ...
    '1100100001', ...
    '0010110001', ...
    '1010100001', ...
    '0110100001', ...
    '0001011110', ...
    '0011001110', ...
    '1001100001', ...
    '0101100001', ...
    '0010011110', ...
    '0011100001', ...
    '0100011110', ...
    '1000011110', ...
    '0101001110', ...
    '1100001011', ...
    '1100000110', ...
    '1100001010', ...
    '1100001100', ...
    '1100001101', ...
    '1100000101', ...
    '1100001001', ...
    '1100000111', ...
    '0001010111', ...
    '0010010111', ...
    '0100010111', ...
    '1000010111'};

% Convert binary string to bit-vector form.
str2vec = @(s) arrayfun(@(c) (c=='1'), s);

% Calculate Hamming distance between two bit-vectors.
hamming = @(a,b) sum(xor(a,b));

% Convert each table to binary matrix form.
nwords = length(rdm_str);
rdm = zeros(nwords, 10);
rdp = zeros(nwords, 10);
for r = 1:nwords
    rdm(r,:) = str2vec(rdm_str{r});
    rdp(r,:) = str2vec(rdp_str{r});
end

% Analyze Hamming distance for each input codeword.
corr_count = 0;
for n = 0:1023
    % Convert codeword to bit-vector form.
    bvec = str2vec(dec2bin(n, 10));
    % Calculate Hamming distance to each valid codeword.
    dist_rdm = arrayfun(@(r) hamming(bvec, rdm(r,:)), 1:nwords);
    dist_rdp = arrayfun(@(r) hamming(bvec, rdp(r,:)), 1:nwords);
    % Is the minimum distance unique?
    min_rdm = min(dist_rdm);
    if (sum(dist_rdm == min_rdm) == 1)
        corr_count = corr_count + 1;
    end
    min_rdp = min(dist_rdp);
    if (sum(dist_rdp == min_rdp) == 1)
        corr_count = corr_count + 1;
    end
end

fprintf(1, 'Correctable errors: %d / 2048\n', corr_count);

end

